#include <err.h>
#include <stdio.h>
#include <fcntl.h>
#include <getopt.h>

#define _GNU_SOURCE
#include <unistd.h>

#include "../getopt_helper.h"

static struct option const LONG_OPTIONS[] = {
	{ "data", no_argument, NULL, 'd' },
	{ "file-system", no_argument, NULL, 'f' },
	GETOPT_END_DECL
};

static const char usage_str[] =
    "Usage: %s [OPTION] [FILE]...\n"
    "Synchronize cached writes to persistent storage\n"
    "\n"
    "If one or more files are specified, sync only them,\n"
    "or their containing file systems.\n"
    "\n"
    "  -d, --data             sync only file data, no unneeded metadata\n"
    "  -f, --file-system      sync the file systems that contain the files\n"
    "      --help             display this help and exit\n"
    "      --version          output version information and exit";

int
main(int argc, char* argv[])
{
	int ch, ret = 0;

	static const int open_flags = O_NOCTTY | O_RDONLY | O_NONBLOCK;

	enum flag INIT_FLAGS(NO, d, f);
	enum flag args = NO;

	while ((ch = getopt_long(argc, argv, "df", LONG_OPTIONS, NULL))
	       != -1) {
		switch (ch) {
			IS_FLAGS(YES, d, f);
			GETOPT_END_CASE
		}
	}

	if (dflag && fflag)
		errx(!0, "cannot specify both --data and --file-system");

	for (argv += optind; *argv; ++argv, args = YES) {
		int fd;

		if ((fd = open(*argv, open_flags)) == -1) {
			warn("error opening '%s'", *argv);
			ret = !0;
			continue;
		}

		int (*sync_ptr)(int);

		if (fflag)
			sync_ptr = syncfs;
		else
			sync_ptr = dflag ? fdatasync : fsync;

		if (!!sync_ptr(fd)) {
			warn("%s", *argv);
			ret = !0;
		}

		close(fd);
	}

	if (!args) {
		if (dflag)
			errx(!0, "--data needs at least one argument");
		else
			sync();
	}

	return ret;
}
